﻿using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Xml.Linq;

namespace LicenseLib
{
    public class LicenseHelper
    {
        [DllImport("user32.dll", CharSet = CharSet.Unicode)]
        public static extern int MessageBox(IntPtr hWnd, String text, String caption, uint type);

        const string RandomChars = "1234567890-=!@#$%^&*()_+`~qwertyuiop[]\asdfghjkl;'zxcvbnm,./QWERTYUIOP{}|ASDFGHJKL:ZXCVBNM<>?";
        const string RandomLetter = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";

        private string _LicensePath = string.Empty;
        private string _LicenseDir = string.Empty;
        private string _LicensePathTemp = string.Empty;
        private string _Key = "&HSDV(^XZDFAS(FSDVSDFASX}{|53FAS";
        private string _IV = "five_E4ghj*Ghg7!rNIfb&2021#er*&2f90F1213Io(u%g6HJ($jhWk7&!hg4ui%$hjk.%five";
        private string _LicenseContent = string.Empty;
        private string _AppName = string.Empty;
        private DateTime validTime = new DateTime();
        private object fileObj = new object();
        /// <summary>
        /// 初始化加密参数
        /// </summary>
        /// <param name="licensePath">许可证路径</param>
        /// <param name="key">加密密钥</param>
        /// <param name="iv">初始化向量</param>
        public void Init(string licensePath, string key, string iv, string appName = "")
        {
            if (!string.IsNullOrEmpty(licensePath))
            {
                _LicensePath = licensePath;
                try
                {
                    _LicenseDir = Path.GetDirectoryName(licensePath);
                    Directory.CreateDirectory(_LicenseDir);
                }
                catch { }
                _LicensePathTemp = $"{_LicenseDir}\\Temp_{Path.GetFileName(_LicensePath)}";
            }
            if (!string.IsNullOrEmpty(key))
                _Key = key ;
            if (!string.IsNullOrEmpty(iv))
                _IV = iv;
            if (!string.IsNullOrEmpty(appName))
                _AppName = appName;
            else
                _AppName = Process.GetCurrentProcess().ProcessName;
        }

        /// <summary>
        /// 获取系统信息 bit0-CPU序列号 bit1-硬盘id bit2-MAC地址
        /// BIOS序列号默认获取
        /// </summary>
        /// <param name="pcCheckKey"></param>
        /// <returns></returns>
        public string GetSystemInfo(string pcCheckKey)
        {
            return MachineConfigManager.GetMachineCodeString(pcCheckKey);
        }

        /// <summary>
        /// 解密
        /// </summary>
        /// <param name="str"></param>
        /// <param name="key"></param>
        /// <param name="iv"></param>
        /// <returns></returns>
        public string StrDecrypto(string str)
        {
            if (string.IsNullOrEmpty(str) || str.TrimEnd('\0') == "") return "";
            RijndaelManaged mobjCryptoService = new RijndaelManaged();
            byte[] bytIn = Convert.FromBase64String(str);
            //byte[] bytIn = Convert.FromBase64String(Convert.ToBase64String(UTF8Encoding.UTF8.GetBytes(str)));
            //byte[] bytIn = UTF8Encoding.UTF8.GetBytes(str);
            MemoryStream ms = new MemoryStream(bytIn, 0, bytIn.Length);
            mobjCryptoService.Key = GetLegalKey(mobjCryptoService);
            mobjCryptoService.IV = GetLegalIV(mobjCryptoService);
            ICryptoTransform encrypto = mobjCryptoService.CreateDecryptor();
            CryptoStream cs = new CryptoStream(ms, encrypto, CryptoStreamMode.Read);
            StreamReader sr = new StreamReader(cs);
            return sr.ReadToEnd();
        }

        /// <summary>
        /// 加密
        /// </summary>
        /// <param name="str"></param>
        /// <param name="key"></param>
        /// <param name="iv"></param>
        /// <returns></returns>
        public string StrEncrypto(string str)
        {
            if (string.IsNullOrEmpty(str) || str.TrimEnd('\0') == "") return "";
            RijndaelManaged mobjCryptoService = new RijndaelManaged();
            byte[] bytIn = UTF8Encoding.UTF8.GetBytes(str);
            //byte[] bytIn = Convert.FromBase64String(str);
            //byte[] bytIn = Convert.FromBase64String(Convert.ToBase64String(UTF8Encoding.UTF8.GetBytes(str)));
            MemoryStream ms = new MemoryStream();
            mobjCryptoService.Key = GetLegalKey(mobjCryptoService);
            mobjCryptoService.IV = GetLegalIV(mobjCryptoService);
            ICryptoTransform encrypto = mobjCryptoService.CreateEncryptor();
            CryptoStream cs = new CryptoStream(ms, encrypto, CryptoStreamMode.Write);
            cs.Write(bytIn, 0, bytIn.Length);
            cs.FlushFinalBlock();
            ms.Close();
            byte[] bytOut = ms.ToArray();
            return Convert.ToBase64String(bytOut);
        }

        /// <summary>
        /// 激活码校验
        /// </summary>
        /// <param name="realCode"></param>
        /// <param name="errorMsg"></param>
        /// <returns></returns>
        public bool ActivateCodeCheck(string realCode, out string errorMsg)
        {
            errorMsg = string.Empty;
            string[] sZ = realCode.Split(';');
            if (sZ.Length != 7 || sZ[0].Length != 3)
            {
                errorMsg = "激活码不正确。";
                return false;
            }
            var machine = GetSystemInfo(sZ[0]);
            string[] machineGroups = machine.Split(';');
            if (machineGroups.Length != 5)
            {
                errorMsg = "硬件信息获取异常。";
                return false;
            }
            //程序校验
            if (sZ[1] != _AppName)
            {
                errorMsg = "应用程序不匹配。";
                return false;
            }
            //BIOS比对
            if (sZ[2] != machineGroups[0])
            {
                errorMsg = "硬件信息不匹配。";
                return false;
            }
            //CPU比对
            if (sZ[0][0] == '1' && sZ[4] != machineGroups[1])
            {
                errorMsg = "硬件信息不匹配。";
                return false;
            }
            //硬盘比对
            if (sZ[0][1] == '1')
            {
                List<string> diskList = sZ[5].Split(',').ToList();
                bool diskFlag = false;
                foreach (var item in diskList)
                {
                    if (machineGroups[2].Contains(item))
                    {
                        diskFlag = true;
                        break;
                    }
                }
                if (!diskFlag)
                {
                errorMsg = "硬件信息不匹配。";
                    return false;
                }
            }
            //网卡比对
            if (sZ[0][2] == '1')
            {
                List<string> macList = sZ[6].Split(',').ToList();
                bool macFlag = false;
                foreach (var item in macList)
                {
                    if (machineGroups[3].Contains(item))
                    {
                        macFlag = true;
                        break;
                    }
                }
                if (!macFlag)
                {
                errorMsg = "硬件信息不匹配。";
                    return false;
                }
            }
            //有效期
            DateTime validTime = DateTime.ParseExact(sZ[3], "yyyyMMdd", new System.Globalization.CultureInfo("en-US", false).DateTimeFormat);
            if ((DateTime.Now - validTime).TotalMilliseconds > 0)
            {
                errorMsg = "授权已过期。";
                return false;
            }
            return true;
        }

        /// <summary>
        /// 创建License
        /// </summary>
        /// <param name="licensePath">License路径</param>
        /// <param name="realCode">License实际值(不包含最后使用时间)</param>
        /// <returns></returns>
        public bool CreateLicense(string licensePath, string realCode)
        {
            try
            {
                string[] infos = realCode.Split(';');
                infos[3] = $"{infos[3]}_{DateTime.Now.ToString("yyyyMMddHHmmss")}";
                realCode = string.Join(";", infos);
                string licenseCode = StrEncrypto(realCode);
                lock (fileObj)
                {
                    using (FileStream fs = new FileStream(licensePath, FileMode.Create))
                    {
                        using (StreamWriter sw = new StreamWriter(fs, Encoding.UTF8))
                        {
                            sw.Write(licenseCode);
                        }
                    }
                    using (FileStream fs = new FileStream(_LicensePathTemp, FileMode.Create))
                    {
                        using (StreamWriter sw = new StreamWriter(fs, Encoding.UTF8))
                        {
                            sw.Write(licenseCode);
                        }
                    }
                }
                return true;
            }
            catch (Exception ex)
            {
                return false;
            }
        }

        /// <summary>
        /// License校验
        /// </summary>
        /// <param name="errorMsg">错误信息</param>
        /// <returns></returns>
        public bool CheckLicense(out string errorMsg)
        {
            errorMsg = string.Empty;
            try
            {
                if (!File.Exists(_LicensePath))
                {
                    errorMsg = "尚未授权。";
                    return false;
                }
                string encryptoContent = string.Empty;
                lock (fileObj)
                {
                    encryptoContent = File.ReadAllText(_LicensePath);
      
                }
                if (!InfoCheck(encryptoContent, out errorMsg))
                {
                    encryptoContent = File.ReadAllText(_LicensePathTemp);
                    return InfoCheck(encryptoContent, out errorMsg);
                }
                return true;
                
            }
            catch (Exception ex)
            {
                errorMsg = ex.Message;
                return false;
            }
        }

        /// <summary>
        /// License信息校验
        /// </summary>
        /// <param name="encryptoContent"></param>
        /// <param name="errorMsg"></param>
        /// <returns></returns>
        private bool InfoCheck(string encryptoContent, out string errorMsg)
        {
            errorMsg = string.Empty;
            if (string.IsNullOrEmpty(encryptoContent))
            {
                return false;
            }
            _LicenseContent = StrDecrypto(encryptoContent);
            string[] infos = _LicenseContent.Split(';');
            Stopwatch sw = Stopwatch.StartNew();
            var machine = GetSystemInfo(infos[0]);
            sw.Stop();
            Console.WriteLine($"SystemInfo:{sw.ElapsedMilliseconds}");
            string[] machineGroups = machine.Split(';');
            if (machineGroups.Length != 5)
            {
                errorMsg = "硬件信息获取异常。";
                return false;
            }
            //程序对比
            if (infos[1] != _AppName)
            {
                errorMsg = "应用程序不匹配。";
                return false;
            }
            //BIOS比对
            if (infos[2] != machineGroups[0])
            {
                errorMsg = "硬件信息不匹配。";
                return false;
            }
            //CPU比对
            if (infos[0][0] == '1' && infos[4] != machineGroups[1])
            {
                errorMsg = "硬件信息不匹配。";
                return false;
            }
            //硬盘比对
            if (infos[0][1] == '1')
            {
                List<string> diskList = infos[5].Split(',').ToList();
                bool diskFlag = false;
                foreach (var item in diskList)
                {
                    if (machineGroups[2].Contains(item))
                    {
                        diskFlag = true;
                        break;
                    }
                }
                if (!diskFlag)
                {
                errorMsg = "硬件信息不匹配。";
                    return false;
                }
            }
            //网卡比对
            if (infos[0][2] == '1')
            {
                List<string> macList = infos[6].Split(',').ToList();
                bool macFlag = false;
                foreach (var item in macList)
                {
                    if (machineGroups[3].Contains(item))
                    {
                        macFlag = true;
                        break;
                    }
                }
                if (!macFlag)
                {
                    errorMsg = "硬件信息不匹配。";
                    return false;
                }
            }
            return UpdateLicenseLastUsedTime(out errorMsg);
        }

        /// <summary>
        /// 读取License配置文件 .xph
        /// </summary>
        /// <param name="path"></param>
        /// <returns></returns>
        public LicenseConfigModel LicenseConfigRead(string path, string appName = "")
        {
            try
            {
                string encryptoContent = File.ReadAllText(path);
                string licenseContent = StrDecrypto(encryptoContent);
                if (string.IsNullOrEmpty(appName)) appName = Process.GetCurrentProcess().ProcessName;
                LicenseConfigModel item = JsonConvert.DeserializeObject<LicenseConfigModel>(licenseContent);
                if (item != null)
                {
                    if (item.Type != appName)
                        return null;

                    //Key混淆
                    string timeString = item.Key.Substring(item.Key.Length - 14, 14);
                    item.Key = item.Key.Remove(item.Key.Length - 14, 14);
                    DateTime time = DateTime.ParseExact(timeString, "yyyyMMddHHmmss", new System.Globalization.CultureInfo("en-US", false).DateTimeFormat);
                    int temp = (time.Year + time.Month + time.Day + time.Hour + time.Minute + time.Second) % 4 + 4;
                    int appendLength = 0;
                    for (int i = 1; i <= temp; i++)
                    {
                        appendLength += i;
                    }
                    int length = (item.Key.Length - appendLength) / temp;
                    for (int i = 0; i < temp; i++)
                    {
                        item.Key = item.Key.Remove((i + 1) * length, temp - i);
                    }

                    //License混淆
                }
                return item;
            }
            catch (Exception ex)
            {
                return null;
            }
        }

        /// <summary>
        /// 更新最近使用时间
        /// </summary>
        /// <param name="errorMsg"></param>
        /// <returns></returns>
        public bool UpdateLicenseLastUsedTime(out string errorMsg)
        {
            errorMsg = string.Empty;
            string[] infos = _LicenseContent.Split(';');
            string[] times = infos[3].Split('_');
            if (times.Length != 2)
            {
                errorMsg = "License数据异常";
                return false;
            }
            //有效期
            validTime = DateTime.ParseExact(times[0], "yyyyMMdd", new System.Globalization.CultureInfo("en-US", false).DateTimeFormat);
            if ((DateTime.Now - validTime).TotalMilliseconds > 0)
            {
                    errorMsg = "授权已过期。";
                return false;
            }

            //最后使用时间
            DateTime lastUsedTime = DateTime.ParseExact(times[1], "yyyyMMddHHmmss", new System.Globalization.CultureInfo("en-US", false).DateTimeFormat);
            if ((DateTime.Now - lastUsedTime).TotalMilliseconds < 0)
            {
                    errorMsg = "系统时间异常。";
                return false;
            }
            infos[3] = times[0];
            return CreateLicense(_LicensePath, $"{string.Join(";", infos)}");
        }


        /// <summary>
        /// 实例化LicenseConfig对象
        /// </summary>
        /// <param name="type"></param>
        /// <param name="path"></param>
        /// <param name="name"></param>
        /// <param name="key"></param>
        /// <returns></returns>
        public LicenseConfigModel CreateLicenseConfig(string type, string name, string key)
        {
            LicenseConfigModel license = new LicenseConfigModel()
            {
                Type = type,
                //LicensePath = $"{System.Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)}Microsoft\\{GetRandomChart()}\\PHX Test Studio License.dll",
                LicensePath = name,
                Key = key,
                //Key = "HC*S&FS*(GSJNGS(DK(CS)FNSIGNSICSNINSIG%#%GSVSG",
                IV = _IV
            };
            return license;
        }

        /// <summary>
        /// 获得密钥
        /// </summary>
        /// <returns>密钥</returns>
        private byte[] GetLegalKey(RijndaelManaged mobjCryptoService)
        {
            string sTemp = _Key;
            mobjCryptoService.GenerateKey();
            byte[] bytTemp = mobjCryptoService.Key;
            int KeyLength = bytTemp.Length;
            if (sTemp.Length > KeyLength)
                sTemp = sTemp.Substring(0, KeyLength);
            else if (sTemp.Length < KeyLength)
                sTemp = sTemp.PadRight(KeyLength, ' ');
            return ASCIIEncoding.ASCII.GetBytes(sTemp);
        }

        /// <summary>
        /// 获得初始向量IV
        /// </summary>
        /// <returns>初试向量IV</returns>
        private byte[] GetLegalIV(RijndaelManaged mobjCryptoService)
        {
            mobjCryptoService.GenerateIV();
            byte[] bytTemp = mobjCryptoService.IV;
            int IVLength = bytTemp.Length;
            if (_IV.Length > IVLength)
                _IV = _IV.Substring(0, IVLength);
            else if (_IV.Length < IVLength)
                _IV = _IV.PadRight(IVLength, ' ');
            return ASCIIEncoding.ASCII.GetBytes(_IV);
        }


        public void SaveLicenseResource(string path, LicenseConfigModel config)
        {
            var resource = LicenseConfigWriteHand(DateTime.Now, config);
            var licenseContent = JsonConvert.SerializeObject(resource);
            var encryptoContent = StrEncrypto(licenseContent);
            using (FileStream fs = new FileStream(path, FileMode.Create))
            {
                using (StreamWriter sw = new StreamWriter(fs, Encoding.UTF8))
                {
                    sw.Write(encryptoContent);
                }
            }
        }

        private LicenseConfigModel LicenseConfigWriteHand(DateTime time, LicenseConfigModel item)
        {
            Random rd = new Random(Guid.NewGuid().GetHashCode());

            int temp = (time.Year + time.Month + time.Day + time.Hour + time.Minute + time.Second) % 4 + 4;

            //Key混淆
            int length = item.Key.Length / temp;
            int appendLength = 0;
            for (int i = 0; i < temp; i++)
            {
                StringBuilder stringBuilder = new StringBuilder();
                for (int j = temp - i; j > 0; j--)
                {
                    stringBuilder.Append(RandomChars[rd.Next(RandomChars.Length)]);
                }
                item.Key = item.Key.Insert((i + 1) * length + appendLength, stringBuilder.ToString());
                appendLength += stringBuilder.Length;
            }
            item.Key += $"{time.ToString("yyyyMMddHHmmss")}";

            //路径混淆
            StringBuilder dirBuilder = new StringBuilder();
            for (int i = 0; i < temp; i++)
            {
                dirBuilder.Append(RandomLetter[rd.Next(RandomLetter.Length)]);
            }
            item.LicensePath = $"{System.Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)}\\Microsoft\\{dirBuilder.ToString()}\\{Path.GetFileName(item.LicensePath)}";
            return item;
        }

        #region Python调用


        /// <summary>
        /// License校验(Python)
        /// </summary>
        /// <param name="path">授权配置文件路径</param>
        /// <param name="appName">授权关联的应用程序名 为空时不启用运行时有效期检测 多个应用程序重名时一并关联</param>
        /// <param name="errorMsg">输出错误信息</param>
        /// <returns></returns>
        public bool Python_CheckLicense(string path, out string errorMsg)
        {           
            LicenseConfigModel model = LicenseConfigRead(path);
            if (model == null)
            {
                errorMsg = "未找到权限配置文件。";
                return false;
            }
            Init(model.LicensePath, model.Key, model.IV, model.Type);
            var result = CheckLicense(out errorMsg);

            System.Timers.Timer timer = new System.Timers.Timer();
            timer.Elapsed += Timer_Elapsed;
            //timer.Interval = 1000 * 60;
            timer.Interval = 1000 * 60;
            timer.Start();

            return result;
        }


        private void Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            var minutes = (validTime - DateTime.Now).TotalMinutes;
            foreach (var app in System.Diagnostics.Process.GetProcesses().Where(t => t.ProcessName == _AppName))
            {
                if (minutes > 0 && minutes <= 1)
                {
                    MessageBox(app.MainWindowHandle, "授权有效期还有1分钟，到期后将退出平台。", "提示", 0);
                }
                else if (minutes < 0)
                {
                    app.Kill();

                }
            }

        }




        #endregion
    }
}
